#include "RenderComponent.h"
#include "DeferredRenderSystem.h"
#include "ModelLoader.h"

IEngineComponentRegistry renderComponentRegistery("RenderComponent", RenderComponent::Deserialize);

RenderComponent::RenderComponent()
{
	this->modelPath = NULL;
	clearRotation();
	clearScale();
	clearPosition();
}

RenderComponent::RenderComponent(char* path, D3DXQUATERNION rotation, D3DXVECTOR3 scale, D3DXVECTOR3 position)
{
	int pathSize = strlen(path);
	modelPath = (char*)malloc((pathSize + 1) * sizeof(char));
	strcpy_s(modelPath, pathSize + 1, path);
	this->rotation = rotation;
	this->scale = scale;
	this->position = position;
}

HRESULT RenderComponent::LoadModel(EnginePointer<ModelLoader> pModelLoader)
{
	HRESULT hr = pModelLoader->LoadModel(modelPath, model);
	if (FAILED(hr)) return hr;

	return S_OK;
}

EnginePointer<Model> RenderComponent::getModel()
{
	return model;
}

void RenderComponent::Serialize(EnginePointer<ISerializerWriteContext>& context, char* name)
{
	context->StartItem(name, "RenderComponent", "1.0");
	context->SerializeProperty("componentId", this->componentId);
	context->SerializeProperty("modelPath", modelPath);
	context->SerializeProperty("positionX", position.x);
	context->SerializeProperty("positionY", position.y);
	context->SerializeProperty("positionZ", position.z);
	context->SerializeProperty("scaleX", scale.x);
	context->SerializeProperty("scaleY", scale.y);
	context->SerializeProperty("scaleZ", scale.z);
	context->SerializeProperty("rotationX", rotation.x);
	context->SerializeProperty("rotationY", rotation.y);
	context->SerializeProperty("rotationZ", rotation.z);
	context->SerializeProperty("rotationW", rotation.w);
	context->EndItem(name);
}

IEngineComponent* RenderComponent::Deserialize(EnginePointer<ISerializerReadContext>& context)
{
	RenderComponent* renderComponent = new RenderComponent();
	int index = 0;
	char* childName = context->ChildName(index);

	while (childName != NULL)
	{
		if (strcmp(childName, "componentId") == 0)
		{
			renderComponent->componentId = context->ChildValueAsULongLong(index);
		}
		else if (strcmp(childName, "modelPath") == 0)
		{
			char* modelPath = context->ChildValue(index);
			renderComponent->setModelPath(modelPath);
		}
		else if(strcmp(childName, "positionX") == 0)
		{
			D3DXVECTOR3 position = renderComponent->getPosition();
			position.x = context->ChildValueAsFloat(index);
			renderComponent->setPosition(position);
		}
		else if(strcmp(childName, "positionY") == 0)
		{
			D3DXVECTOR3 position = renderComponent->getPosition();
			position.y = context->ChildValueAsFloat(index);
			renderComponent->setPosition(position);
		}
		else if(strcmp(childName, "positionZ") == 0)
		{
			D3DXVECTOR3 position = renderComponent->getPosition();
			position.z = context->ChildValueAsFloat(index);
			renderComponent->setPosition(position);
		}
		else if(strcmp(childName, "scaleX") == 0)
		{
			D3DXVECTOR3 scale = renderComponent->getScale();
			scale.x = context->ChildValueAsFloat(index);
			renderComponent->setScale(scale);
		}
		else if(strcmp(childName, "scaleY") == 0)
		{
			D3DXVECTOR3 scale = renderComponent->getScale();
			scale.y = context->ChildValueAsFloat(index);
			renderComponent->setScale(scale);
		}
		else if(strcmp(childName, "scaleZ") == 0)
		{
			D3DXVECTOR3 scale = renderComponent->getScale();
			scale.z = context->ChildValueAsFloat(index);
			renderComponent->setScale(scale);
		}
		else if(strcmp(childName, "rotationX") == 0)
		{
			D3DXQUATERNION rotation = renderComponent->getRotation();
			rotation.x = context->ChildValueAsFloat(index);
			renderComponent->setRotation(rotation);
		}
		else if(strcmp(childName, "rotationY") == 0)
		{
			D3DXQUATERNION rotation = renderComponent->getRotation();
			rotation.y = context->ChildValueAsFloat(index);
			renderComponent->setRotation(rotation);
		}
		else if(strcmp(childName, "rotationZ") == 0)
		{
			D3DXQUATERNION rotation = renderComponent->getRotation();
			rotation.z = context->ChildValueAsFloat(index);
			renderComponent->setRotation(rotation);
		}
		else if(strcmp(childName, "rotationW") == 0)
		{
			D3DXQUATERNION rotation = renderComponent->getRotation();
			rotation.w = context->ChildValueAsFloat(index);
			renderComponent->setRotation(rotation);
		}
		childName = context->ChildName(++index);
	}
	
	return renderComponent;
}

GUID RenderComponent::getSystemIdentifier()
{
	return RENDER_SYSTEM_GUID;
}

GUID RenderComponent::getComponentIdentifier()
{
	return RENDER_COMPONENT_GUID;
}

D3DXMATRIX RenderComponent::getWorld()
{
	D3DXMATRIX mScale;
	D3DXMATRIX mRotate;
	D3DXMATRIX mPosition;

	D3DXMatrixScaling(&mScale, scale.x, scale.y, scale.z);
	D3DXMatrixRotationQuaternion(&mRotate,& rotation);
	D3DXMatrixTranslation(&mPosition, position.x, position.y, position.z);
	return mScale*mRotate*mPosition;
}

void RenderComponent::clearRotation()
{
	D3DXQuaternionIdentity(&rotation);
}

void RenderComponent::setRotation(D3DXQUATERNION rotation)
{
	rotation = rotation;
}

void RenderComponent::rotate(D3DXVECTOR3 axis, float angle)
{
	D3DXQuaternionRotationAxis(&rotation,& axis, angle);
}

D3DXQUATERNION RenderComponent::getRotation()
{
	return rotation;
}

void RenderComponent::clearPosition()
{
	position = D3DXVECTOR3(0,0,0);
}

void RenderComponent::setPosition(D3DXVECTOR3 position)
{
	this->position = position;
}

void RenderComponent::move(D3DXVECTOR3 movement)
{
	position += movement;
}

D3DXVECTOR3 RenderComponent::getPosition()
{
	return position;
}

void RenderComponent::clearScale()
{
	scale = D3DXVECTOR3(1,1,1);
}

void RenderComponent::setScale(D3DXVECTOR3 scale)
{
	this->scale = scale;
}

void RenderComponent::doScale(D3DXVECTOR3 scale)
{
	this->scale.x *= scale.x;
	this->scale.y *= scale.y;
	this->scale.z *= scale.z;
}

D3DXVECTOR3 RenderComponent::getScale()
{
	return scale;
}

void RenderComponent::setModelPath(char *modelPath)
{
	free(this->modelPath);
	int pathSize = strlen(modelPath);
	this->modelPath = (char*)malloc((pathSize + 1) * sizeof(char));
	strcpy_s(this->modelPath, pathSize + 1, modelPath);
}